//#node
import path from "path"
import { mkdirSync, readFile, writeFile, writeFileSync } from 'fs'
import chalk from 'chalk'
import { createCode, createExport, createFun, createImport, createObj, createRetuen, createUseFun, createVar } from "./module.js"
import { createFunAnn, createVarAnn } from "./annotation.js"
import { appendFile, readdir } from "fs/promises"

/**
 * 
 * @param { string } filepath json文件目录
 * @param { string } outpath 输出目录
 * @param { number } version 使用的输出版本号
 */
function p2a(filepath, outpath, version) {

    readFile(filepath, "utf-8", async (e, d) => {
        if (e === null) {
            try {
                if (!outpath) {
                    outpath = "api"
                }
                if (version === 0) {
                    /**
                    * @type { import("./postman").PostManCollectionItem[] }
                    */
                    let data = JSON.parse(d).item
                    await createAxiosInitFile(outpath)
                    createAPI(data, outpath)
                }
            } catch {
                console.log(chalk.red(`json文件解析错误 ${e.path}`));
            }
        }
        else {
            console.error(chalk.red(`找不到文件 ${e.path}`))
        }
    })
}

/**
 * 参数解析调动代码生成
 * @param { string } outpath 
 * @param { import("./postman").PostManCollectionItem[] } items 
 */
async function createAPI(items, outpath) {
    const pathSet = new Set()
    items.forEach((d) => {
        if (d.item) {
            let fileName = d.name.replaceAll(" ", "") + ".js"
            let filecode = createCode([
                createImport(['request'], "./index.js")
            ])
            d.item.forEach((i) => {
                filecode += createRequsetCode(i, pathSet)
            })
            writeFile(path.join(outpath, fileName), filecode, { 'encoding': 'utf-8' }, () => { })
        } else if (d.request) {
            let code = createRequsetCode(d, pathSet)
            appendFile(path.join(outpath, "index.js"), code)
        }
    })
}

/**
 * 生成请求代码
 * @param { import("./postman").PostManRequest } req 
 * @param { Set<string> } set
 * @returns { string }
 */
function createRequsetCode(req, set) {
    const p = req.request.url?.path?.join("/") || ""
    let code = ""
    const funName = formatName(req.name)
    if (!set.has(p)) {
        set.add(p)
        code += createCode([
            createVarAnn([{ "type": "import('@b-hole/axios').BAxios", "des": req.request.description || "无描述" }]),
            createVar("const", funName + "REQ", `request('${p}')`),
            createExport([funName + "REQ"])
        ])
    }
    let reqMethod = ""
    let ann = [{ "type": "import('axios').AxiosRequestConfig", "name": "config", "des": "axios 请求设置" }]
    let ann1 = [{ "type": "any", "name": "data", "des": "请求数据" }]
    let param = ['config']
    let paramList = ['data']
    switch (req.request.method) {
        case "GET":
            reqMethod = 'get'
            break
        case "POST":
            reqMethod = 'post'
            ann = ann.concat(ann1)
            param = paramList.concat(param)
            break
        case "PUT":
            reqMethod = 'put'
            ann = ann.concat(ann1)
            param = paramList.concat(param)
            break
        case "DELETE":
            reqMethod = 'delete'
            break
    }
    if (req.request?.body?.mode == "formdata") {
        reqMethod += 'Form'
    }
    code += createCode([
        createFunAnn(ann, { type: "Promise", "des": "结果" }, req.request.description),
        createFun(funName, param, [
            createRetuen(`request('${p}').${reqMethod}(${param.join(",")})`)
        ]),
        createExport([funName])
    ])
    return code
}


/**
 * 
 * 创建 axios 引入文件
 */
async function createAxiosInitFile(outpath) {
    const file = createCode([
        createImport(['createBAxios'], "@b-hole/axios"),
        createVar("const", "request",
            createUseFun("createBAxios", createObj({
                baseURL: "location.origin + '/api/'",
                withCredentials: true,
                timeout: 5000
            }))),
        createExport(['request']),
        'request.onReqError((err)=>{})',
        'request.onResError((err)=>{})',
        'request.onErrMsg((msg)=>{})',
        'request.onSuccMsg((msg)=>{})',
    ])
    try {
        await readdir(outpath)
    } catch (e) {
        mkdirSync(outpath)
    }
    finally {
        writeFileSync(path.join(outpath, "index.js"), file, { 'encoding': 'utf-8' })
    }
}

function formatName(name){
    return name.replaceAll(/[\^\$\.\*\+\?\(\)\[\]\{\}\|\\\/\-\=\@\#\!\%\&\:\'\";,\~\`， ]/ig, "").replaceAll(/^\d+/ig, "")
}
export { p2a }